package com.zhz.mall.common.exception;


import cn.hutool.core.exceptions.ExceptionUtil;
import com.zhz.mall.common.api.CommonResult;
import com.zhz.mall.common.api.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolationException;
import java.util.Objects;


/**
 * 全局异常处理
 *
 * @author zhouhengzhe
 */
@RestControllerAdvice(basePackages = "com.zhz.mall")
public class GlobalExceptionHandler {

    /**
     * 捕获 {@code BusinessException} 异常
     */
    @ExceptionHandler({BusinessException.class})
    public CommonResult<String> handleBusinessException(BusinessException ex) {
        return CommonResult.failed(ex.getMessage());
    }

    /**
     * 捕获 {@code ForbiddenException} 异常
     */
    @ExceptionHandler({ForbiddenException.class})
    public CommonResult<ResultCode> handleForbiddenException(ForbiddenException ex) {
        return CommonResult.failed(ResultCode.FORBIDDEN);
    }


    @ExceptionHandler(value = ApiException.class)
    public CommonResult handle(ApiException e) {
        if (Objects.nonNull(e.getErrorCode())) {
            return CommonResult.failed(e.getErrorCode());
        }
        return CommonResult.failed(e.getMessage());
    }


    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public CommonResult handleValidException(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        StringBuilder sb = new StringBuilder("校验失败:");
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            sb.append(fieldError.getField()).append("：").append(fieldError.getDefaultMessage()).append(",");
        }
        String msg = sb.toString();
        if (StringUtils.hasText(msg)) {
            return CommonResult.failed(ResultCode.VALIDATE_FAILED, msg);
        }
        return CommonResult.failed(ResultCode.VALIDATE_FAILED);
    }

    @ExceptionHandler(value = BindException.class)
    public CommonResult handleValidException(BindException e) {
        BindingResult bindingResult = e.getBindingResult();
        String message = null;
        if (bindingResult.hasErrors()) {
            FieldError fieldError = bindingResult.getFieldError();
            if (Objects.nonNull(fieldError)) {
                message = fieldError.getField() + fieldError.getDefaultMessage();
            }
        }
        return CommonResult.validateFailed(message);
    }

    /**
     * {@code @PathVariable} 和 {@code @RequestParam} 参数校验不通过时抛出的异常处理
     */
    @ExceptionHandler({ConstraintViolationException.class})
    public CommonResult handleConstraintViolationException(ConstraintViolationException ex) {
        if (StringUtils.hasText(ex.getMessage())) {
            return CommonResult.failed(ResultCode.VALIDATE_FAILED, ex.getMessage());
        }
        return CommonResult.failed(ResultCode.VALIDATE_FAILED);
    }

    /**
     * 顶级异常捕获并统一处理，当其他异常无法处理时候选择使用
     */
    @ExceptionHandler({Exception.class})
    public CommonResult handle(Exception ex) {
        return CommonResult.failed(ex.getMessage());
    }
}
